ChristmasError-Blog

C++ RBTree红黑树的实现

字数统计: 2.7k阅读时长: 15 min
2018/11/17 Share

红黑树的性质

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个根节点是红色的,则它的两个叶子结点是黑色的(没有两个连续的红色结点)
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点(每条路径上黑色结点的数量相等)
  5. 所有叶子结点为黑(与平时不同,这里的叶子结点是指空的叶子结点,即为NULL)

红黑树是一种特殊的二叉查找树,这意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键值,小于等于右孩子的键值。(相较于二叉查找树,我们只要对结点的颜色进行判断和调整)。
红黑树虽然复杂,但它的最坏情况运行时间也是非常良好的,它可以在O(log n)时间内做查找,插入和删除(n是树中结点树)。

红黑树结点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//RBTNode.h
enum RBTColor { Black, Red };

template<class KeyType>
struct RBTNode
{
KeyType key;
RBTColor color;
RBTNode<KeyType> * left;
RBTNode<KeyType> * right;
RBTNode<KeyType> * parent;
RBTNode(KeyType k, RBTColor c, RBTNode* p, RBTNode*l, RBTNode*r) :
key(k), color(c), parent(p), left(l), right(r) { };
};

红黑树的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
//RBTree.h
#include"RBTNode.h"
#include <iomanip>

template<class T>
class RBTree
{
public:
RBTree();
~RBTree();

void insert(T key); //插入结点,key为键值,外部接口
void remove(T key); //删除key的节点
RBTNode<T>* search(T key);
void print();
void preOrder(); //前序遍历 打印红黑树
void inOrder(); //中序遍历
void postOrder(); //后序遍历



private:
void leftRotate(RBTNode<T>* &root, RBTNode<T>* x);// 左旋
void rightRotate(RBTNode<T>* &root, RBTNode<T>* y);// 右旋

void insert(RBTNode<T>* &root, RBTNode<T>* node);// 插入结点,内部接口
void InsertFixUp(RBTNode<T>* &root, RBTNode<T>* node);
void destory(RBTNode<T>* &node);

void remove(RBTNode<T>*& root, RBTNode<T>*node);//删除为KEY的结点
void removeFixUp(RBTNode<T>* &root, RBTNode<T>* node, RBTNode<T>*parent);

RBTNode<T>* search(RBTNode<T>*node, T key) const;
void print(RBTNode<T>* node)const;
void preOrder(RBTNode<T>* tree)const;
void inOrder(RBTNode<T>* tree)const;
void postOrder(RBTNode<T>* tree)const;
private:
RBTNode<T>*root;
};

template<class T> //构造函数
RBTree<T>::RBTree() :root(NULL) {
root = nullptr;
}
template<class T> //析构函数
RBTree<T>::~RBTree() {
destory(root);
}
template<class T> //左旋
void RBTree<T>::leftRotate(RBTNode<T>* &root, RBTNode<T>* x) {
RBTNode<T>*y = x->right;
x->right = y->left;
if (y->left != NULL)
y->left->parent = x;

y->parent = x->parent;
if (x->parent == NULL)
root = y;
else {
if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
}
y->left = x;
x->parent = y;
};
template<class T> //右旋
void RBTree<T>::rightRotate(RBTNode<T>*&root, RBTNode<T>*y) {
RBTNode<T>*x = y->left;
y->left = x->right;
if (x->right != NULL)
x->right->parent = y;

x->parent = y->parent;
if (y->parent == NULL)
root = x;
else {
if (y == y->parent->right)
y->parent->right = x;
else
y->parent->left = x;
}
x->right = y;
y->parent = x;
};
template<class T> //插入
void RBTree<T>::insert(T key)
{
RBTNode<T>*z = new RBTNode<T>(key, Red, NULL, NULL, NULL);
insert(root, z);
};
template<class T>
void RBTree<T>::insert(RBTNode<T>* &root, RBTNode<T>* node)
{
RBTNode<T> *x = root;
RBTNode<T> *y = NULL;
while (x != NULL)
{
y = x;
if (node->key > x->key)
x = x->right;
else
x = x->left;
}
node->parent = y;
if(y!=NULL)
{
if (node->key > y->key)
y->right = node;
else
y->left = node;
}
else
root = node;
node->color = Red;
InsertFixUp(root, node);
};
template<class T>
void RBTree<T>::InsertFixUp(RBTNode<T>* &root, RBTNode<T>* node)
{
RBTNode<T>*parent;
parent = node->parent;
while (node != RBTree::root && parent->color == Red)
{
RBTNode<T>*gparent = parent->parent;
if (gparent->left == parent)
{
RBTNode<T>*uncle = gparent->right;
if (uncle != NULL && uncle->color == Red)
{
parent->color = Black;
uncle->color = Black;
gparent->color = Red;
node = gparent;
parent = node->parent;
}
else
{
if (parent->right == node)
{
leftRotate(root, parent);
swap(node, parent);
}
rightRotate(root, gparent);
gparent->color = Red;
parent->color = Black;
break;
}
}
else
{
RBTNode<T>*uncle = gparent->left;
if (uncle != NULL && uncle->color == Red)
{
gparent->color = Red;
parent->color = Black;
uncle->color = Black;

node = gparent;
parent = node->parent;
}
else
{
if (parent->left == node)
{
rightRotate(root, parent);
swap(parent, node);
}
leftRotate(root, gparent);
parent->color = Black;
gparent->color = Red;
break;
}
}
}
root->color = Black;
}
template<class T>
//销毁红黑树
void RBTree<T>::destory(RBTNode<T>* &node)
{
if (node == NULL)
return;
destory(node->left);
destory(node->right);
delete node;
node = nullptr;
}

template<class T>
void RBTree<T>::remove(T key)
{
RBTNode<T>*deletenode = search(root,key);
if (deletenode != NULL)
remove(root, deletenode);
}
template<class T>
void RBTree<T>::remove(RBTNode<T>*&root, RBTNode<T>*node)
{
RBTNode<T> *child, *parent;
RBTColor color;
//被删除节点左右结点都不为空(不为叶子结点)
if (node->left != NULL && node->right != NULL)
{
RBTNode<T> *replace = node;
//找后继结点(当前节点的右子树的最下层的左结点)
replace = node->right;
while (replace->left != NULL)
{
replace = replace->left;
}
//被删节点不为根节点情况
if (node->parent != NULL)
{
if (node->parent->left == node)
node->parent->left = replace;
else
node->parent->right = replace;
}
//根节点情况
else
root = replace;
//child是取代节点的右结点,是需要后续调整的结点
//因为replace是后继结点,因此他不可能有左子节点
//同理前驱结点不可能有右子节点
child = replace->right;
parent = replace->parent;
color = replace->color;

//被删结点是取代结点(repalce)的父节点的情况
if (parent == node)
parent = replace;
else
{
//child结点存在的情况
if (child != NULL)
child->parent = parent;
parent->left = child;

replace->right = node->right;
node->right->parent = replace;
}
replace->parent = node->parent;
replace->color = node->color;
replace->left = node->left;
node->left->parent = replace;
if (color == Black)
removeFixUp(root, child, parent);

delete node;
return;
}
//当被删节点只有左(右)结点为空情况,找出被删结点的子节点
if (node->left != NULL)
child = node->left;
else
child = node->right;

parent = node->parent;
color = node->color;
if (child)
{
child->parent = parent;
}
//被删除节点不为根节点
if (parent)
{
if (node == parent->left)
parent->left = child;
else
parent->right = child;
}
//被删除节点为根节点
else
RBTree::root = child;

if (color == Black)
{
removeFixUp(root, child, parent);
}
delete node;

}
template<class T>
void RBTree<T>::removeFixUp(RBTNode<T>* &root, RBTNode<T>* node,RBTNode<T>*parent)
{
RBTNode<T>*othernode;
while ((!node) || node->color == Black && node != RBTree::root)
{
if (parent->left == node)
{
othernode = parent->right;
if (othernode->color == Red)
{
othernode->color = Black;
parent->color = Red;
leftRotate(root, parent);
othernode = parent->right;
}
else
{
if (!(othernode->right) || othernode->right->color == Black)
{
othernode->left->color=Black;
othernode->color = Red;
rightRotate(root, othernode);
othernode = parent->right;
}
othernode->color = parent->color;
parent->color = Black;
othernode->right->color = Black;
leftRotate(root, parent);
node = root;
break;
}
}
else
{
othernode = parent->left;
if (othernode->color == Red)
{
othernode->color = Black;
parent->color = Red;
rightRotate(root, parent);
othernode = parent->left;
}
if ((!othernode->left || othernode->left->color == Black) && (!othernode->right || othernode->right->color == Black))
{
othernode->color = Red;
node = parent;
parent = node->parent;
}
else
{
if (!(othernode->left) || othernode->left->color == Black)
{
othernode->right->color = Black;
othernode->color = Red;
leftRotate(root, othernode);
othernode = parent->left;
}
othernode->color = parent->color;
parent->color = Black;
othernode->left->color = Black;
rightRotate(root, parent);
node = root;
break;
}
}
}
if (node)
node->color = Black;
}

template<class T>
RBTNode<T>* RBTree<T>::search(T key)
{
return search(root, key);
}
template<class T>
RBTNode<T>* RBTree<T>::search(RBTNode<T>*node, T key) const
{
if (node == NULL || node->key == key)
return node;
else
if (key > node->key)
return search(node->right, key);
else
return search(node->left, key);
}
template<class T> //输出二叉树详细信息
void RBTree<T>::print() {
if (root == NULL)
cout << "empty RBtree\n";
else
print(root);
}
template<class T>
void RBTree<T>::print(RBTNode<T>* node)const {
if (node == NULL)
return;
if (node->parent == NULL)
cout << node->key << "(" << node->color << ") is root" << endl;
else if(node->parent->left==node)
{
cout << node->key << "(" << node->color << ") is "<<node->parent->key<<"'s "<<"left child" << endl;
}
else
{
cout << node->key << "(" << node->color << ") is " << node->parent->key << "'s " << "right child" << endl;
}
print(node->left);
print(node->right);
}
template<class T> //前序遍历RB
void RBTree<T>::preOrder() {
if (root == NULL)
cout << "empty RBtree\n";
else
preOrder(root);
};
template<class T>
void RBTree<T>::preOrder(RBTNode<T>* tree)const {
if (tree != NULL) {
cout << tree->key << " ";
preOrder(tree->left);
preOrder(tree->right);
}
}
template<class T> //中遍历RB
void RBTree<T>::inOrder() {
if (root == NULL)
cout << "empty RBtree\n";
else
inOrder(root);
};
template<class T>
void RBTree<T>::inOrder(RBTNode<T>* tree)const {
if (tree != NULL) {
inOrder(tree->left);
cout << tree->key << " ";
inOrder(tree->right);
}
}
template<class T> //后遍历RB
void RBTree<T>::postOrder() {
if (root == NULL)
cout << "empty RBtree\n";
else
postOrder(root);
};
template<class T>
void RBTree<T>::postOrder(RBTNode<T>* tree)const {
if (tree != NULL) {
postOrder(tree->left);
postOrder(tree->right);
cout << tree->key << " ";
}
}

因为RBTree这里使用模板 ,因此不能将cpp和h文件的RBTree的声明和实现分离
原因:
模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。
在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。——《C++编程思想》第15章300页处

红黑树测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//test.cpp
#include"RBTree.h"
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> nums{ 10,40,30,60,90,70,20,50,80,100};
RBTree<int> tree;
for (auto num : nums)
tree.insert(num);
tree.preOrder();
cout << endl;
tree.inOrder();
cout << endl;
tree.postOrder();
cout << endl;
cout << "查找key为30的结点:\n";
cout << endl<<tree.search(30)->key<<endl;
cout << "删除key为100的结点\n";
tree.remove(100);
tree.preOrder();
cout << endl;
cout << "\n红黑树详细信息:\n";
tree.print();
cin.get();
return 0;
}

测试运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
60 30 10 20 40 50 80 70 90 100
10 20 30 40 50 60 70 80 90 100
20 10 50 40 30 70 100 90 80 60
查找key为30的结点:

30
删除key为100的结点
60 30 10 20 40 50 80 70 90

红黑树详细信息:
60(0) is root
30(1) is 60's left child
10(0) is 30's left child
20(1) is 10's right child
40(0) is 30's right child
50(1) is 40's right child
80(1) is 60's right child
70(0) is 80's left child
90(0) is 80's right child
CATALOG
  1. 1. 红黑树的性质
  2. 2. 红黑树结点
  3. 3. 红黑树的实现
  4. 4. 红黑树测试
  5. 5. 测试运行结果